package com.example.BlockChain.utils.http;

import com.example.BlockChain.entity.NoticeParams;
import com.example.BlockChain.entity.block.Block;
import com.example.BlockChain.entity.block.BlockDownLoad;
import com.example.BlockChain.service.impl.BlockServiceImpl;
import com.google.gson.Gson;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.nio.charset.Charset;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

public class HttpHelper {
    private static final Logger LOGGER = LoggerFactory.getLogger(HttpHelper.class);

    /**
     * 下载区块数据的方法。
     *
     * @param ip 区块服务的IP地址
     * @param port 区块服务的端口号
     * @param np 通知参数对象，包含请求的详细信息
     * @return 返回封装的区块下载结果对象
     */
    public static BlockDownLoad downLoadBlock(String ip, int port, NoticeParams np) {
        BlockDownLoad bdl = new BlockDownLoad(); // 创建区块下载结果对象
        String url = ""; // 初始化请求的URL
        if (StringUtils.isNotBlank(ip)) {
            url = "http://" + ip + ":" + port + "/mining/server/block.zip"; // 使用参数中的IP和端口拼接URL
        } else {
            url = "http://" + np.getIp() + ":" + "8001" + "/mining/server/block.zip"; // 使用默认的端口拼接URL
        }

        // 创建HttpClient对象，用于执行HTTP请求
        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response = null;
        ZipInputStream zis = null; // 用于解析下载的ZIP压缩文件
        HttpPost httpPost = null;

        try {
            System.out.println("Download Block "); // 打印下载信息
            httpPost = new HttpPost(url); // 创建POST请求
            httpPost.setHeader("Content-type", "application/json; charset=utf-8");
            httpPost.setHeader("Connection", "Close");
            httpPost.addHeader("Accept-Encoding", "GZIP");

            // 配置请求的超时时间
            RequestConfig requestConfig = RequestConfig.custom()
                    .setConnectTimeout(5000) // 连接超时
                    .setConnectionRequestTimeout(15000) // 请求超时
                    .setSocketTimeout(15000) // 响应超时
                    .build();
            httpPost.setConfig(requestConfig);

            // 设置请求体为JSON格式
            StringEntity entity = new StringEntity(np.toJSONString(), Charset.forName("UTF-8"));
            entity.setContentEncoding("UTF-8");
            entity.setContentType("application/json");
            httpPost.setEntity(entity);

            // 执行HTTP请求
            response = httpClient.execute(httpPost);

            // 解析返回的ZIP文件
            zis = new ZipInputStream(response.getEntity().getContent(), Charset.forName("UTF-8"));
            ZipEntry ze = null;
            Block block = null;
            String blockFileStr = "";
            String maxIndex = "";

            // 遍历ZIP文件中的每个条目
            while ((ze = zis.getNextEntry()) != null) {
                if ("blockObject".equals(ze.getName())) {
                    // 如果是区块对象，调用BlockServiceImpl解析
                    block = BlockServiceImpl.getBlockObeject(zis);
                } else if ("maxBlockIndex".equals(ze.getName())) {
                    // 如果是最大块编号，调用BlockServiceImpl解析
                    maxIndex = BlockServiceImpl.getMaxBlockIndexStr(zis);
                } else if ("blockFile".equals(ze.getName())) {
                    // 如果是区块文件，调用BlockServiceImpl解析
                    blockFileStr = BlockServiceImpl.getBlockFileStr(zis);
                    System.out.println(blockFileStr);
                }
            }

            // 检查区块内容是否完整
            if (block == null || StringUtils.isBlank(blockFileStr)) {
                System.out.println("当前block为空，无需下载");
            }

            // 设置下载结果
            bdl.setBlock(block);
            bdl.setBlockFileStr(blockFileStr);
            bdl.setMaxBlockIndex(maxIndex);
            return bdl; // 返回结果
        } catch (Exception e) {
            System.out.println("连接不到对等节点：" + ip);
        } finally {
            try {
                if (httpPost != null) {
                    httpPost.releaseConnection(); // 释放HTTP连接
                }
                if (httpClient != null) {
                    httpClient.close(); // 关闭HttpClient
                }
                if (response != null) {
                    response.close(); // 关闭响应
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 验证区块的方法。
     *
     * @param ip 服务端IP地址
     * @param block 需要验证的区块对象
     * @return 验证结果的字符串
     */
    public static String checkBlock(String ip, Block block) {
        CloseableHttpResponse response = null;
        HttpPost httpPost = null;
        try {
            // 将区块对象转为JSON字符串
            String senMsg = new Gson().toJson(block);

            // 构造POST请求
            httpPost = new HttpPost("http://" + ip + ":8001/mining/checkBlock");
            RequestConfig requestConfig = RequestConfig.custom()
                    .setConnectTimeout(5000)
                    .setConnectionRequestTimeout(15000)
                    .setSocketTimeout(15000)
                    .build();
            httpPost.setConfig(requestConfig);

            // 创建HttpClient
            CloseableHttpClient httpClient = HttpClients.createDefault();

            // 设置请求体
            StringEntity entity = new StringEntity(senMsg, Charset.forName("UTF-8"));
            entity.setContentEncoding("UTF-8");
            entity.setContentType("application/json");
            httpPost.setEntity(entity);

            // 执行请求
            response = httpClient.execute(httpPost);

            // 检查响应状态码
            if (200 == response.getStatusLine().getStatusCode()) {
                // 返回验证结果
                String resultString = EntityUtils.toString(response.getEntity(), "utf-8");
                return resultString;
            } else {
                return "Request failed: " + response.getStatusLine().getStatusCode() + " ";
            }
        } catch (ClientProtocolException e) {
            e.getMessage();
        } catch (IOException e) {
            e.getMessage();
        } catch (Exception e) {
            e.getMessage();
        } finally {
            try {
                if (httpPost != null) {
                    httpPost.releaseConnection();
                }
                if (response != null) {
                    response.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }
}
